/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2005
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
* 
* Author's email :    insane@dees.ufmg.br
* Author's website :  http://www.dees.ufmg.br/insane
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package br.ufmg.dees.insane.persistence.PostpPersistence;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
import java.util.ListIterator;
import java.util.Observable;
import java.util.Observer;
import java.util.StringTokenizer;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import br.ufmg.dees.insane.model.postp.Boundary;
import br.ufmg.dees.insane.model.postp.GeoPostpModel;
import br.ufmg.dees.insane.model.postp.Patch;
import br.ufmg.dees.insane.model.postp.PointModel;
import br.ufmg.dees.insane.model.postp.StepPostp;
import br.ufmg.dees.insane.persistence.Persistence;
import br.ufmg.dees.insane.util.IPoint3d;

/** A class representing postpPersistenceAsXML
 * @author Samuel Silva Penna
 * @since 27/08/2005
 */
public class PostpPersistenceAsXML implements Persistence, Observer {

	 /**
	 * Comment for <code>serialVersionUID</code>
	 */
	private static final long serialVersionUID = 1L;

	/** The Model of this persistence. */
	protected static StepPostp stepPostp;
	
	/** The Object which will be serialized. */
	protected static Object docOutput;
	
	private boolean isValid = true;
  
	/** Returns the Model of this application.
	*@return The Model of this application.
	*/
	public StepPostp getStep(){
		return (stepPostp);
	}
	
	/** Sets the Model of this application.
	*@param a The Model of this application.
	*/
	public void setStepPostp(StepPostp s){
		stepPostp = s;
	}
	
  /* (non-Javadoc)
   * @see br.ufmg.dees.insane.persistence.Persistence#fillModelfromFile(java.lang.String)
   */
  public void fillInsaneFromFile(String File) {
      
  	//Creating and configuring the SAXParser
  	SAXParserFactory parserFac = SAXParserFactory.newInstance();
  	
  	parserFac.setValidating(true);
  	
  	try
  	{
  		SAXParser parser = parserFac.newSAXParser();
  		
  		//implementing DefaultHandler
  		parser.parse(File, new DefaultHandler()
  		{
  			StringBuffer content = new StringBuffer();

  			//All the classes which will be instantiated are declared here
  			ArrayList<PointModel> pointsList;
  			ArrayList<Patch> patchesList;
  			ArrayList<Boundary> boundariesList;
  			ArrayList<GeoPostpModel> geoPostpModelList;
  			PointModel point;
  			Boundary boundary;
  			Patch patch;
  			GeoPostpModel geoPostpModel;
  			IPoint3d coord;
  			
  			public void setDocumentLocator(Locator locator){
  				
  			}
  			 
  			public void characters(char ch[], int start, int length){
  				this.content.append(ch, start, length);
  			}
  			
  			//todos os ifs deste metodo serao ativados quando o parser encontrar <....>
  			public void startElement(String uri, String localName, String qName, Attributes attributes)
  			{
  				if ("PostpData".equals(qName)){
  				}
  				
  				else if ("Step".equals(qName)){
  					stepPostp = new StepPostp();
                  	stepPostp.setLabel(attributes.getValue("label"));
  				}
  				
  				//Read "<StepValues ...>"
  				else if ("StepAttributes".equals(qName)){
  				}
  				
  				else if ("GeoPostpModelList".equals(qName)){
  					geoPostpModelList = new ArrayList<GeoPostpModel>();
  				}
  				
  				else if ("GeoPostpModel".equals(qName)){
  					geoPostpModel = new GeoPostpModel();
  				}
  				
  			    
  				//Read "<PointsList ...>"
  				else if ("PointsList".equals(qName)){
  					pointsList = new ArrayList<PointModel>();
  				}

  				//Read "<PointModel ...>"
  				else if ("PointModel".equals(qName)){
  					point = new PointModel();
  					point.setLabel(attributes.getValue("label"));
  				}
  				
  				//Read "<coord ...>"
  				else if ("Coord".equals(qName)){
  					coord = new IPoint3d();
  				}
  				
  				//Read "<Restraints ...>"
  				else if ("Value".equals(qName)){
  					
  				}
                  
  				//Read "<PatchesList ...>"
                  else if ("PatchesList".equals(qName)){
                  	patchesList = new ArrayList<Patch>();
                  }
  				
  				//Read "<Patch ...>"
  				else if ("Patch".equals(qName)){
                      patch = new Patch();
                      patch.setLabel(attributes.getValue("label"));
  				}
  						
  				//Read "<patchPointsLabels ...>"
  				else if ("PatchPointsLabels".equals(qName)){
  					
  				}
                  
  				//Read "<BoundariesList ...>"
                  else if ("BoundariesList".equals(qName)){
                  	boundariesList = new ArrayList<Boundary>();
                  }
                  
  				//Read "<Boundary ...>"
  				else if ("Boundary".equals(qName)){
  					boundary = new Boundary();
  					boundary.setLabel(attributes.getValue("label"));
  				}
			
  				//Read "<patchPointsLabels ...>"
  				else if ("BoundPointsLabels".equals(qName)){
  					
  				}
  				
  			} // END OF STAR ELEMENT*********************************************
	    			
  			//    todos os ifs deste metodo serao ativados quando o parser encontrar </....>
  			public void endElement(String uri, String localName, String qName)
  			{
  				
  				if ("PostpData".equals(qName)){
  					
  				}
  				
  				else if ("GeoPostpModelList".equals(qName)){
  					
  				}
  				
  				else if ("GeoPostpModel".equals(qName)){
  					geoPostpModel.setPoints(pointsList);
  					geoPostpModel.setBoundaries(boundariesList);
  					geoPostpModel.setPatches(patchesList);
  					geoPostpModelList.add(geoPostpModel);
  				}
  				
  				//Read "</PointsList>"
  				else if ("PointsList".equals(qName)){
  					
  				}
                  
  				//Read "</PointModel>"
  				else if ("PointModel".equals(qName)){
  					if(!checkPoint(this.point,this.pointsList)){
  						this.pointsList.add(this.point);
  					}
  				}
  				
  				//Read "</coord>"
  				else if ("Coord".equals(qName)){
  				    StringTokenizer stk = new StringTokenizer(content.toString());
  					coord.x = Double.parseDouble(stk.nextToken());
  					coord.y = Double.parseDouble(stk.nextToken());
  					coord.z = Double.parseDouble(stk.nextToken());
  					point.setCoord(coord);
  				}
  				
  				//Read "</value>"
  				else if ("Value".equals(qName)){
  					StringTokenizer stk = new StringTokenizer(content.toString());
  					Object o1 = (String)stk.nextToken();
  					Object o2 = stk.nextToken();
  					if(o1.equals("RESTRAINTS-Dx")||o1.equals("RESTRAINTS-Dy")||o1.equals("RESTRAINTS-Dz")
  							||o1.equals("RESTRAINTS-Dx")||o1.equals("RESTRAINTS-Dy")||o1.equals("RESTRAINTS-Rz")){
  						point.putValue((String)o1,Boolean.parseBoolean((String)o2));
  					}else{
  						point.putValue((String)o1,Double.parseDouble((String)o2));
  					}
  				}

  				//Read "</PatchesList ...>"
  				else if ("PatchesList".equals(qName)){
  					
  				}
                  
  				//Read "</Patch ...>"
  				else if ("Patch".equals(qName)){
  					patchesList.add(patch);
  				}
  				
  				//Read "</patchPointsLabels ...>"
  				else if ("PatchPointsLabels".equals(qName)){
  					StringTokenizer stk = new StringTokenizer(content.toString());
  				    int cont = stk.countTokens();
  					String[] patchPoints = new String[cont];
  					for(int i=0;i<cont;i++){
  						patchPoints[i] = stk.nextToken();
  					}
  					patch.setPointsLabels(patchPoints);
  				}
                  
  				//Read "</BoundariesList ...>"
  				else if ("BoundariesList".equals(qName)){
  					
  				}
                 
//                Read "</Boundary ...>"
  				else if ("Boundary".equals(qName)){
  					boundariesList.add(boundary);
  				}
  				
//  				Read "<boundPointsLabels ...>"
  				else if ("BoundPointsLabels".equals(qName)){
  					StringTokenizer stk = new StringTokenizer(content.toString());
  				    int cont = stk.countTokens();
  					String[] boundaryPoints = new String[cont];
  					for(int i=0;i<cont;i++){
  						boundaryPoints[i] = stk.nextToken();
  					}
  					boundary.setPointsLabels(boundaryPoints);
  				}
  				else if ("Step".equals(qName)){
                  stepPostp.setGeoPostpModelList(geoPostpModelList);
  				}
 			
// 				Read "</stepAttributes>"
 				 	else if ("stepAttributes".equals(qName))
 				 	{
 				 		StringTokenizer stk = new StringTokenizer(content.toString());
 				 		stepPostp.putStepValue(stk.nextToken(),new Double(Double.parseDouble(stk.nextToken())));
 				 	}
  	
               content = new StringBuffer();
                  
  			}//END OF ENDELEMENT*********************************************
  			
  		});//END OF PARSE*******************************************************
  		
  	}//END OF TRY*******************************************************************
  		
  	catch (ParserConfigurationException pce){
  		System.out.println("Could not create that parser.");
  		System.out.println(pce.getMessage());
  		
  		//System.exit(1);
  	}
  	catch (SAXException se){
  		System.out.println("Problem with the SAX parser.");
  		System.out.println(se.getMessage());
  		//System.exit(2);
  	}
  	catch (IOException ioe){
  		System.out.println("Error reading file.");
  		System.out.println(ioe.getMessage());
  		this.isValid = false;
  		//System.exit(3);
  	}
  	
  }//END OF FILLMODELFROMFILE**********************************************************
  

  /* (non-Javadoc)
   * @see br.ufmg.dees.insane.persistence.Persistence#fillFileFromModel(java.lang.String)
   */
  public void fillFileFromModel() {
	  
	  try{
		  DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		  Document doc = builder.newDocument();
		  
		  //Creating formator
		  DecimalFormat fmt = new DecimalFormat();
		  DecimalFormatSymbols fsym = new DecimalFormatSymbols();
		  fsym.setDecimalSeparator('.');
		  fmt.setDecimalFormatSymbols(fsym);
		  
		  //All the classes which will be instantiated are declared here
		  PointModel point;
		  Boundary boundary;
		  Patch patch;
		  
		  //Creating root DOM element "PostpData"
		  org.w3c.dom.Element root = doc.createElement("PostpData");
		  doc.appendChild(root);
		  
		  //Creating DOM element "Step"
		  org.w3c.dom.Element elemStep = doc.createElement("Step");
		  elemStep.setAttribute("label", "" + stepPostp.getLabel());
		  root.appendChild(elemStep);
		  
		  //Creating DOM element "GeoPostpModelList"
		  org.w3c.dom.Element elemGeoPostpModelList = doc.createElement("GeoPostpModelList");
		  elemStep.appendChild(elemGeoPostpModelList);
		  
		  //Creating DOM elements "GeoPostpModel"
		  ListIterator geoPostpModelIT = stepPostp.getGeoPostpModelList().listIterator();
		  while (geoPostpModelIT.hasNext()){
			  GeoPostpModel geoPostpModel = (GeoPostpModel)geoPostpModelIT.next();
			  
			  //Creating DOM element "GeoPostpModel"
			  org.w3c.dom.Element elemGeoPostpModel = doc.createElement("GeoPostpModel");
			  elemGeoPostpModel.setAttribute("label", "" + geoPostpModel.getLabel());
			  elemGeoPostpModelList.appendChild(elemGeoPostpModel);
			  
			  //Creating DOM element "PointsList"
			  org.w3c.dom.Element elemPointsList = doc.createElement("PointsList");
			  elemGeoPostpModel.appendChild(elemPointsList);
			  
			  //Creating DOM elements "PointModel"
			  ListIterator pointsIT = geoPostpModel.getPoints().listIterator();
			  while (pointsIT.hasNext()){
				  point = (PointModel)pointsIT.next();
				  
				  org.w3c.dom.Element elemPointModel = doc.createElement("PointModel");
				  elemPointModel.setAttribute("label", "" + point.getLabel());
				  elemPointsList.appendChild(elemPointModel);
				  
				  //Creating DOM elements "Coord"
				  org.w3c.dom.Element elemCoord = doc.createElement("Coord");
				  fmt.applyPattern("0.0000E00");
				  elemCoord.appendChild(doc.createTextNode(String.valueOf(fmt.format(point.getX()))));
				  elemCoord.appendChild(doc.createTextNode(" "));
				  elemCoord.appendChild(doc.createTextNode(String.valueOf(fmt.format(point.getY()))));
				  elemCoord.appendChild(doc.createTextNode(" "));
				  elemCoord.appendChild(doc.createTextNode(String.valueOf(fmt.format(point.getZ()))));
				  elemPointModel.appendChild(elemCoord);
				  
				  //Creating DOM elements "value"
				  for(int j=0;j<point.getKeys().size();j++){
					  org.w3c.dom.Element elemValue = doc.createElement("Value");
					  elemValue.appendChild(doc.createTextNode((String)point.getKeys().get(j)));
					  elemValue.appendChild(doc.createTextNode(" "));
					  elemValue.appendChild(doc.createTextNode(String.valueOf(point.getValue((String)point.getKeys().get(j)))));
					  elemValue.appendChild(doc.createTextNode(" "));
					  elemPointModel.appendChild(elemValue);
				  }
			  }
			  
			  //Creating DOM element "PointsList"
			  org.w3c.dom.Element elemPatchesList = doc.createElement("PatchesList");
			  elemGeoPostpModel.appendChild(elemPatchesList);
			  
			  //Creating DOM elements "Patch"
			  ListIterator patchesIT = geoPostpModel.getPatches().listIterator();
			  while (patchesIT.hasNext()){
				  patch = (Patch)patchesIT.next();
				  org.w3c.dom.Element elemPatch = doc.createElement("Patch");
				  elemPatch.setAttribute("label", "" + patch.getLabel());
				  elemPatchesList.appendChild(elemPatch);
				  
				  //Creating DOM elements "patchPointsLabels"
				  org.w3c.dom.Element elemPatchPointsLabels = doc.createElement("PatchPointsLabels");
				  for(int i=0;i<patch.getPointsLabels().length;i++){
					  elemPatchPointsLabels.appendChild(doc.createTextNode(patch.getPointsLabels()[i]));
					  elemPatchPointsLabels.appendChild(doc.createTextNode(" "));
					  elemPatch.appendChild(elemPatchPointsLabels);
				  }
				  
			  }//End of creating DOM element "Patch"
			  
			  //Creating DOM element "BoundariesList"
			  org.w3c.dom.Element elemBoundariesList = doc.createElement("BoundariesList");
			  elemGeoPostpModel.appendChild(elemBoundariesList);
			  
			  //Creating DOM elements "Boundary"
			  ListIterator boundariesIT = geoPostpModel.getBoundaries().listIterator();
			  while (boundariesIT.hasNext()){
				  boundary = (Boundary)boundariesIT.next();
				  //Creating DOM element "Boundary"
				  org.w3c.dom.Element elemBoundary = doc.createElement("Boundary");
				  elemBoundary.setAttribute("label", "" + boundary.getLabel());
				  elemBoundariesList.appendChild(elemBoundary);
				  
				  //Creating DOM elements "BoundPointsLabels"
				  org.w3c.dom.Element elemBoundPointsLabels = doc.createElement("BoundPointsLabels");
				  for(int i=0;i<boundary.getPointsLabels().length;i++){
					  elemBoundPointsLabels.appendChild(doc.createTextNode(boundary.getPointsLabels()[i]));
					  elemBoundPointsLabels.appendChild(doc.createTextNode(" "));
					  elemBoundary.appendChild(elemBoundPointsLabels);
				  }
				  
			  }//End of creating DOM element "Boundary"
			  
		  }
		  
//		  Creating DOM elements "stepAttributes"
		  for(int j=0;j<stepPostp.getKeys().size();j++){
			  org.w3c.dom.Element elemStepAttributes = doc.createElement("StepAttributes");
			  elemStepAttributes.appendChild(doc.createTextNode((String)stepPostp.getKeys().get(j)));
			  elemStepAttributes.appendChild(doc.createTextNode(" "));
			  elemStepAttributes.appendChild(doc.createTextNode(String.valueOf(fmt.format(stepPostp.getStepValue((String)stepPostp.getKeys().get(j))))));
			  elemStepAttributes.appendChild(doc.createTextNode(" "));
			  elemStep.appendChild(elemStepAttributes);
		  }
		  
		  docOutput = doc;
	  } //end of try 
	  
	  catch (ParserConfigurationException pce){
		  System.out.println("Could not create DOM parser.");
		  System.out.println(pce.getMessage());
		  System.exit(4);
	  }
	  
  }
  
  /** Serializes the DOM tree into a XML file.
	*@param resultFile The name of the output file.
	*/
  public void serializeDOMTreeIntoXMLDocument(String resultFile) {
		try {
			TransformerFactory tf = TransformerFactory.newInstance();
			tf.setAttribute("indent-number", new Integer(4));
			Transformer t = tf.newTransformer();
			t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "insane.dtd");
			t.setOutputProperty(OutputKeys.INDENT, "yes");
			t.setOutputProperty(OutputKeys.ENCODING, "ISO8859-1");
			t.transform(new DOMSource((Document) docOutput),new StreamResult(new FileWriter(resultFile)));
		} catch (TransformerException te) {
			System.out.println("Problem serializing DOM tree");
			System.out.println(te.getMessageAndLocation());
			System.exit(1);
		} catch (IOException e) {
			System.out.println("Problem serializing DOM tree");
			System.out.println(e.getLocalizedMessage());
			System.exit(1);
		}
	}
	

  /* (non-Javadoc)
   * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
   */
  public void printFile() {
  	 File newdir0 = new File("RESULTS");
       if (newdir0.mkdir());
       File newdir1;
       if(newdir0.getAbsolutePath()+File.separator+stepPostp.getLabel()==null){
      	 newdir1 = new File(newdir0.getAbsolutePath()+File.separator+stepPostp.getLabel());
       }
       newdir1 = new File(newdir0.getAbsolutePath()+File.separator+stepPostp.getLabel());
       if (newdir1.mkdir());
       File newdir = new File(newdir1.getAbsolutePath()+File.separator+"XMLs");
       if (newdir.mkdir());
       this.fillFileFromModel();
       
           File newdir2 = new File(newdir1.getAbsolutePath()+File.separator+"XMLs");
           if (newdir2.mkdir());
           this.fillFileFromModel();
           this.serializeDOMTreeIntoXMLDocument(newdir.getAbsolutePath()+File.separator+"Result-"+stepPostp.getLabel()+".xml");
       
   
  }
  int cont = 1 ;
  public void update(Observable arg0, Object arg) {
//  	String label = stepPostp.getLabel();
//  	stepPostp = (GeoPostpModel)(((StepPostp)((FemModelToPostpModel)arg0).getStepPostp())).getGeoPostpModelList().get(0);
//  	stepPostp.setLabel(label);
//
//  	File newdir0 = new File("RESULTS");
//      if (newdir0.mkdir());
//      File newdir1 = new File(newdir0.getAbsolutePath()+File.separator+stepPostp.getLabel());
//      if (newdir1.mkdir());
//      File newdir = new File(newdir1.getAbsolutePath()+File.separator+"XMLs");
//      if (newdir.mkdir());
//      this.fillFileFromModel();
//
//      DecimalFormat fmt = new DecimalFormat();
//      fmt.applyPattern("000");
//      this.serializeDOMTreeIntoXMLDocument(newdir.getAbsolutePath()+File.separator+stepPostp.getLabel()+"-STEP-"+fmt.format(cont)+".xml");
//      
//      cont++;
 
  }

	public boolean checkPoint(PointModel point, ArrayList pointList){
		boolean compare = false;
		ListIterator itr = pointList.listIterator();	
		while(itr.hasNext()){
			PointModel p = (PointModel)itr.next();
			if(p.getLabel().equals(point.getLabel())){
				compare = true;
				return compare;
			}else{
				 continue;
			}
		}
	return compare;
	}
	
	public PointModel searchElementNode(PointModel point, ArrayList pointList){
		PointModel p = new PointModel();
		ListIterator itr = pointList.listIterator();	
		while(itr.hasNext()){
			p = (PointModel)itr.next();
			if(p.getLabel().equals(point.getLabel())){
				return  p;
			 }else{
				 continue;
			 }
		}
	return null;
	}
  
  
	/**
	 * The method return the isValid.
	 * @return Returns The isValid.
	 */
	public boolean isValid() {
		return isValid;
	}

	/**
	 * The method set the field isValid from the parameter isValid.
	 * @param isValid The isValid to set.
	 */
	public void setValid(boolean isValid) {
		this.isValid = isValid;
	}

//****************************************************************************************************************************	
}//end of this Class
